﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using AdaptiveAgents.Games;
using AdaptiveAgents.Agents;
using AdaptiveAgents.Loggers;
using AdaptiveAgents;
using AdaptiveAgents.Distributions;
namespace GameAnalyzer
{
    public partial class frmLauncher : Form
    {
        private const string DISTRIBUTION_FOLDER = "..//..//..//AdaptiveAgentsV2//Distributions";
        
        //Consts that used in table columns
        private const int PLAYER_NAME = 0;
        private const int PLAYER_TYPE = 1;
        private const int PLAYER_EPS = 2;
        private const int PLAYER_DISTRIBUTION = 3;
        private const int PLAYER_IDISTRIBUTION = 4;

        //Consts of greek symbols
        private const string MU = "μ";
        private const string SIGMA_SQUARE = "σ²";
        private const string LAMBDA = "λ";

        private DataSet _dsGame;
        private IDistribution _dist;

        private int nameCounter = 0;

        public frmLauncher(String gameName)
        {
            InitializeComponent();
            _dsGame = new DataSet(gameName);
        }

        public DataSet getGameData()
        {
            return _dsGame;
        }

        private void Launcher_Load(object sender, EventArgs e)
        {
            //Set game type combobox values
            cbGameType.Items.AddRange(Enum.GetNames(typeof(AdaptiveAgents.Games.GameType)));
            
            //Set player type combobox values
            cbPlayerType.Items.Add("Normal");

            //Set distribution type combobox values
            cbDistribution.Items.AddRange(Enum.GetNames(typeof(DistributionType)));
            
            System.IO.DirectoryInfo directory = new System.IO.DirectoryInfo(DISTRIBUTION_FOLDER);
            System.IO.FileInfo[] files = directory.GetFiles();

            //String[] distFiles = System.IO.Directory.GetFiles("..//..//..//AdaptiveAgents//Distributions");

            foreach (System.IO.FileInfo info in files)
            {
                if (!info.Extension.Equals(".cs"))
                    cbDistFile.Items.Add(info.Name);
            }

            cbPlayerType.SelectedIndex = 0;
            cbGameType.SelectedIndex = 0;
            cbDistribution.SelectedIndex = 0;

            tbName.Text = "Agent " + nameCounter;
        }

        private void btnAddPlayer_Click(object sender, EventArgs e)
        {
            if (tbName.Text == "Agent " + nameCounter)
                ++nameCounter;

            String[] values = new String[4];
            values[PLAYER_NAME] = tbName.Text;
            values[PLAYER_TYPE] = cbPlayerType.Text;
            values[PLAYER_EPS] = nudEpsilon.Value.ToString();

            //Add distribution values
            String dist = cbDistribution.Text;
            //TODO - create IDIstribution according to the parameters
            if (dist.Equals("Uniform"))
                _dist = new Uniform();
            else if (dist.Equals("Exponential"))
                _dist = new Exponential((double)nudParam1.Value);
            else if (dist.Equals("Gaussian"))
                _dist = new Gaussian((double)nudParam1.Value, (double)nudParam2.Value);
            else if (dist.Equals("Blocks"))
            {

            }
                //dist += String.Format(": {0} {1}", lblParam1.Text, nudParam1.Value);
                
              //  if (lblParam2.Visible)
               //     dist += String.Format(", {0} {1}", lblParam2.Text, nudParam2.Value);
            //}
            //else if (dist.Equals("Blocks"))
            //{
            //    //Blocks distribution
            //    dist += ": ";

            //    //Check if file was selected
            //    if (cbDistFile.Text.Length > 0)
            //        dist += cbDistFile.Text;
            //    else
            //    {
            //        //Custom distribution was selected
            //        //dist += btnCustomStep.Tag;
            //        dist += _dist.describe();
            //    }
            //}
            
            //TODO - add describe of distribiution
            //values[PLAYER_DISTRIBUTION] = dist;
            values[PLAYER_DISTRIBUTION] = _dist.ToString();

            ListViewItem item = new ListViewItem(values);
            item.Tag = _dist;//add I distribution
            lvPlayers.Items.Add(item);

            tbName.Text = "Agent " + nameCounter;

            if (lvPlayers.Items.Count > 1)
                btnLaunch.Enabled = true;
        }

        private void tbName_TextChanged(object sender, EventArgs e)
        {
            if (tbName.Text.Length == 0)
                btnAddPlayer.Enabled = false;
            else
                btnAddPlayer.Enabled = true;
        }

        private void btnResetPlayer_Click(object sender, EventArgs e)
        {
            lvPlayers.Items.Clear();
            nameCounter = 0;
            tbName.Text = "Agent " + nameCounter;
            cbPlayerType.SelectedIndex = 0;
            cbDistribution.SelectedIndex = 0;
            nudEpsilon.Value = nudEpsilon.Maximum / 2;
            btnAddPlayer.Enabled = true;
            btnLaunch.Enabled = false;
        }

        private void lvPlayers_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyData)
            {
                case Keys.Delete:
                case Keys.Back:
                    foreach (ListViewItem item in lvPlayers.SelectedItems)
                        lvPlayers.Items.Remove(item);
                    break;
            }
        }

        private void btnOpReset_Click(object sender, EventArgs e)
        {
            nudRounds.Value = 50;
            cbGameType.SelectedIndex = 0;
            cbDistribution.SelectedIndex = 0;
        }

        private void btnLaunch_Click(object sender, EventArgs e)
        {
            tspbGameProgress.Value = 0;
            sttsStrip.Visible = true;

            String fileName = launchGame(); //Get the game file

            sttsStrip.Visible = false;
            
            //Launch analyzer window
            frmAnalyzer frmAnalyzer = new frmAnalyzer(fileName);
            frmAnalyzer.ShowDialog();
        }

        private string launchGame()
        {
            //Create Game Logger
            String stamp = DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss");
            ContainerLogger logger = new ContainerLogger();

            String fileName = "Game" + stamp + ".xml";
            logger.Add(new AdaptiveAgents.Loggers.XmlLogger(fileName));
            
            /*
            //Create environment
            AdaptiveAgents.EnvironmentType env = new AdaptiveAgents.EnvironmentType();
          
            //Create game
            GameType type = (GameType)Enum.Parse(typeof(GameType),cbGameType.SelectedItem.ToString());
            Game game = GameFactory.create(type, env, (int)nudRounds.Value);


            //Create players
            for (int i = 0; i < lvPlayers.Items.Count; ++i)
            {
                ListViewItem player = lvPlayers.Items[i];

                AgentDirector director = new AgentDirector();

                //Choose builder
                if (player.SubItems[PLAYER_TYPE].Text.Equals("Normal"))
                    director.Builder = new NormalBuilder();

                //Construct agent
                director.construct(player.Index, env,Double.Parse(player.SubItems[PLAYER_EPS].Text), logger);
        
                Agent agent = director.getAgent();

                //Set agent's competence
                
                Distribution dist = new Distribution((Distribution.DistributionTypes)
                    Enum.Parse(typeof(Distribution.DistributionTypes),player.SubItems[PLAYER_DISTRIBUTION].Text));
                //HACK - fix distribution read from file. should be inside the class
                //System.IO.File.OpenRead("../../../AdaptiveAgents/Distributions/distribution." + i);
                dist.read("../../../AdaptiveAgentsV2/Distributions/distribution." + i);
                agent.Competence=dist;
                //Add agent to the environment
                env.addAgent(agent);
            }

            //Start the game
            game.start(logger);

            MessageBox.Show("Done!", "Launcher", MessageBoxButtons.OK);
            logger.Close();
            */
            return fileName;
        }

        private void btnAnalyze_Click(object sender, EventArgs e)
        {
            new frmAnalyzer().ShowDialog();
        }

        private void lblShowDist_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            //Get the distribution type
            DistributionType type = (DistributionType)Enum.Parse(typeof(DistributionType), 
                cbDistribution.Text.ToString());

            //Create new instance of frmDistribution
            frmDistribution frmDist = new frmDistribution();

            //Distribution class for drawing the graph
            IDistribution dist = null;

            //Choose which distribution to show
            switch (type)
            {
                case DistributionType.Gaussian:
                    dist = new Gaussian((double)nudParam1.Value, (double)nudParam2.Value);
                    frmDist.createCurve(String.Format("Gaussian {0}={1}, {2}={3}",
                        MU, nudParam1.Value,SIGMA_SQUARE,nudParam2.Value),
                         "Gaussian", dist.sample());
                    break;
                case DistributionType.Exponential:
                        dist = new Exponential((double)nudParam1.Value);
                        frmDist.createCurve(String.Format("Exponential {0}=", LAMBDA, nudParam1.Value),
                            "Exponential", dist.sample());
                        break;
                case DistributionType.Uniform:
                    dist = new Uniform();
                    frmDist.createSteps("Uniform","Uniform",dist.sample());
                    break; 
            }
            frmDist.ShowDialog();
        }

        private void cbDistribution_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Get the distribution type
            DistributionType type = (DistributionType)Enum.Parse(typeof(DistributionType),
                cbDistribution.Text.ToString());

            //Choose which distribution to show
            switch (type)
            {
                case DistributionType.Gaussian:
                    btnAddPlayer.Enabled = true;
                    pnlDistributionParam.Visible = true;
                    lblParam1.Text = MU + " =";
                    lblParam1.Visible = true;
                    nudParam1.Value = 0.5m;
                    nudParam1.Visible = true;
                    nudParam2.Value = 1.0m;
                    lblParam2.Visible = true;
                    lblParam2.Text = SIGMA_SQUARE+ " =";
                    nudParam2.Visible = true;
                    cbDistFile.Visible = false;
                    btnCustomStep.Visible = false;
                    break;
                case DistributionType.Exponential:
                    btnAddPlayer.Enabled = true;
                    pnlDistributionParam.Visible = true;
                    lblParam1.Text = LAMBDA +" =";
                    lblParam1.Visible = true;
                    nudParam1.Value = 0.5m;
                    nudParam1.Visible = true;
                    lblParam2.Visible = false;
                    nudParam2.Visible = false;
                    cbDistFile.Visible = false;
                    btnCustomStep.Visible = false;
                    break;
                case DistributionType.Uniform:
                    btnAddPlayer.Enabled = true;
                    pnlDistributionParam.Visible = false;
                    break;
                case DistributionType.Blocks:
                    btnAddPlayer.Enabled = false;
                    pnlDistributionParam.Visible = true;
                    lblParam1.Visible = false;
                    nudParam1.Visible = false;
                    lblParam2.Visible = false;
                    nudParam2.Visible = false;
                    cbDistFile.Visible = true;
                    btnCustomStep.Visible = true;
                    break;
                    
            }
        }

        private void btnCustomStep_Click(object sender, EventArgs e)
        {
            _dist = frmStepDistributionCreator.createStepDistribution();

            if (_dist == null)
                btnAddPlayer.Enabled = false;
            else
            {
                btnAddPlayer.Enabled = true;
                //btnCustomStep.Tag = _dist.describe();
            }
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            //Create a data table containing game parameters
            DataTable dtGame = new DataTable("Parameters");
            dtGame.Columns.Add("NumOfPlayers", typeof(int));
            dtGame.Columns.Add("GameType", typeof(string));
            dtGame.Columns.Add("Rounds", typeof(int));

            //Create a data table containing players parameters
            DataTable dtPlayers = new DataTable("Players");
            dtPlayers.Columns.Add("Type", typeof(String));
            dtPlayers.Columns.Add("Epsilon", typeof(double));
            dtPlayers.Columns.Add("Distribution", typeof(String));
            dtPlayers.Columns.Add("IDistribution", typeof(IDistribution));

            //Fill data tables with data
            dtGame.Rows.Add(lvPlayers.Items.Count, cbGameType.Text, (int)nudRounds.Value); //Fill game parameters

            for (int i = 0; i < lvPlayers.Items.Count; ++i)
            {
                ListViewItem player = lvPlayers.Items[i];

                dtPlayers.Rows.Add(player.SubItems[PLAYER_TYPE].Text,
                    player.SubItems[PLAYER_EPS].Text,
                    player.SubItems[PLAYER_DISTRIBUTION].Text,
                    player.Tag);
            }

            _dsGame.Tables.Add(dtGame);
            _dsGame.Tables.Add(dtPlayers);
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            lblParam2.Text = "";
            cbDistFile.SelectedIndex = -1;
        }

        private void cbDistFile_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbDistFile.Text.Length == 0)
                return;

            _dist = new Blocks(DISTRIBUTION_FOLDER + "//" + cbDistFile.Text);
            btnAddPlayer.Enabled = true;
        }

        private void nudRounds_ValueChanged(object sender, EventArgs e)
        {

        }
    }
}
